using System;
using System.Collections.Generic;
using System.Text;

namespace SavedVariablesParser.Line {
    /// <summary>
    /// Provides an abstract base class for <see cref="ILine"/> objects.
    /// </summary>
    public abstract class LineBase : ILine{
        /// <summary>
        /// The text of the line.
        /// </summary>
        protected string text = string.Empty;
        /// <summary>
        /// Specifies the type of line.
        /// </summary>
        protected LineType type = LineType.NotSupported;
        /// <summary>
        /// Specifies the line number within the original file where this line can be found.
        /// </summary>
        protected int lineNumber = 0;

        #region ILine Members

        /// <summary>
        /// The text of the line.
        /// </summary>
        public string Text {
            get {
                return this.text;
            }
        }

        /// <summary>
        /// Specifies the type of line.
        /// </summary>
        public LineType Type {
            get {
                return this.type;
            }
        }

        /// <summary>
        /// Specifies the line number within the original file where this line can be found.
        /// </summary>
        public int LineNumber {
            get {
                return this.lineNumber;
            }
        }

        /// <summary>
        /// Renders the line and returns a string representing the rendered value.
        /// </summary>
        /// <returns>The text line rendered in a predefined format.</returns>
        public abstract string Render();

        /// <summary>
        /// Renders the line to the supplied <see cref="StringBuilder"/>.
        /// </summary>
        /// <param name="builder">The <see cref="StringBuilder"/> to render the string to.</param>
        public abstract void Render(StringBuilder builder);

        #endregion

        /// <summary>
        /// Removes all instances of the tab character from a string.
        /// </summary>
        /// <param name="line">The line to remove tab characters from.</param>
        /// <returns>The original string with tab characters replaced by <see cref="string.Empty"/>.</returns>
        protected string PurgeTabs(string line) {
            return line.Replace("\t", string.Empty).Trim();
        }

        /// <summary>
        /// Converts all forbidden characters to thier HTML counterpart.
        /// </summary>
        /// <param name="line">The line to convert characters in.</param>
        /// <returns>The original line with the forbidden characters converted.</returns>
        protected string EscapeForbiddenCharacters(string line) {
            return line.Replace("<", "&lt;").Replace(">", "&gt;").Replace("'", "&apos;").Replace("&", "&amp;").Replace("\"", "&quot;");
        }

        #region Equality Methods

        /// <summary>
        /// Determines if two <see cref="LineBase"/> objects have the same value.
        /// </summary>
        /// <param name="x">The first <see cref="LineBase"/> object to compare.</param>
        /// <param name="y">The second <see cref="LineBase"/> object to compare.</param>
        /// <returns>true if the first <see cref="LineBase"/> is equal to the second <see cref="LineBase"/>; otherwise, false.</returns>
        /// <filterpriority>2</filterpriority>
        public static bool Equals(LineBase x, LineBase y) {
            if ((object)x == (object)y) {
                return true;
            }

            if ((object)x == null || (object)y == null) {
                return false;
            }

            if (x.Text.Equals(y.Text)) {
                return true;
            }

            return false;
        }

        /// <summary>Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>.</summary>
        /// <param name="obj">The <see cref="T:System.Object"/> to compare with the current <see cref="T:System.Object"/>.</param>
        /// <returns>true if the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>; otherwise, false.</returns>
        /// <filterpriority>2</filterpriority>
        public override bool Equals(object obj) {
            LineBase equals = obj as LineBase;
            if (equals != null) {
                return LineBase.Equals(this, equals);
            }
            return false;
        }

        /// <summary>
        /// Determines whether the specified <see cref="LineBase"/> is equal to the current <see cref="LineBase"/>.
        /// </summary>
        /// <param name="lineBase">The <see cref="LineBase"/> to compare with the current <see cref="LineBase"/>.</param>
        /// <returns>true if the specified <see cref="LineBase"/> is equal to the current <see cref="LineBase"/>; otherwise, false.</returns>
        public bool Equals(LineBase lineBase) {
            return LineBase.Equals(this, lineBase);
        }

        /// <summary>
        /// Determines if two <see cref="LineBase"/> objects have the same value.
        /// </summary>
        /// <param name="x">The first <see cref="LineBase"/> object to compare.</param>
        /// <param name="y">The second <see cref="LineBase"/> object to compare.</param>
        /// <returns>true if the first <see cref="LineBase"/> is equal to the second <see cref="LineBase"/>; otherwise, false.</returns>
        public static bool operator ==(LineBase x, LineBase y) {
            return LineBase.Equals(x, y);
        }

        /// <summary>
        /// Determines if two <see cref="LineBase"/> objects have the same value.
        /// </summary>
        /// <param name="x">The first <see cref="LineBase"/> object to compare.</param>
        /// <param name="y">The second <see cref="LineBase"/> object to compare.</param>
        /// <returns>false if the first <see cref="LineBase"/> is equal to the second <see cref="LineBase"/>; otherwise, true.</returns>
        public static bool operator !=(LineBase x, LineBase y) {
            return !LineBase.Equals(x, y);
        }

        #endregion

        /// <summary>Serves as a hash function for a particular type. <see cref="M:System.Object.GetHashCode"/> is suitable for use in hashing algorithms and data structures like a hash table.</summary>
        /// <returns>A hash code for the current <see cref="LineBase"/>.</returns>
        /// <filterpriority>2</filterpriority>
        public override int GetHashCode() {
            return this.text.GetHashCode();
        }
    }
}
